package top.zywork.controller;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import top.zywork.annotation.SysLog;
import top.zywork.dos.UserWithdrawDO;
import top.zywork.dto.UserWalletDTO;
import top.zywork.enums.WithdrawStatusEnum;
import top.zywork.enums.WithdrawTypeEnum;
import top.zywork.security.JwtUser;
import top.zywork.security.SecurityUtils;
import top.zywork.service.UserWalletService;
import top.zywork.service.UserWithdrawService;
import top.zywork.vo.ResponseStatusVO;

import java.math.BigDecimal;

/**
 * 用户提现控制器类<br/>
 *
 * 创建于2018-12-23<br/>
 *
 * @author http://zywork.top 王振宇
 * @version 1.0
 */
@RestController
@RequestMapping("/withdraw")
public class UserWithdrawController extends BaseController {

    private UserWithdrawService userWithdrawService;

    private UserWalletService userWalletService;

    /**
     * 提交提现申请
     *
     * @param withdrawType 提现方式，如提现到银行卡，提现到微信钱包，提现到支付宝钱包
     * @param clientApp 提现发起的应用，如微信，微信小程序，抖音小程序等
     * @param amount 提现金额
     * @param bankcardId 提现银行卡，只有在withdrawType为提现到银行卡时可用
     * @param payPassword 本系统内设置的支付密码
     * @return
     */
    @PostMapping("user/submit")
    @SysLog(description = "用户提交提现申请", requestParams = false)
    public ResponseStatusVO submitWithdraw(Integer withdrawType, Integer clientApp, BigDecimal amount, @RequestParam(required = false) Long bankcardId, @RequestParam(required = false) String payPassword) {
        JwtUser jwtUser = SecurityUtils.getJwtUser();
        if (amount == null) {
            return ResponseStatusVO.dataError("必须填写提现金额", null);
        }
        if (withdrawType == null || clientApp == null) {
            return ResponseStatusVO.dataError("必须填写提现方式及发起提现的应用", null);
        }
        if (withdrawType.intValue() == WithdrawTypeEnum.BANKCARD.getValue().intValue() && bankcardId == null) {
            return ResponseStatusVO.dataError("提现到银行卡必须选择一张银行卡", null);
        }
        if (amount.compareTo(new BigDecimal(0)) <= 0) {
            return ResponseStatusVO.dataError("提现金额必须大于0", null);
        }
        Object obj = userWalletService.getById(jwtUser.getUserId());
        if (obj == null) {
            return ResponseStatusVO.dataError("用户无钱包记录", null);
        }
        if (StringUtils.isNotEmpty(payPassword)) {
            UserWalletDTO userWalletDTO = (UserWalletDTO) obj;
            if (!new BCryptPasswordEncoder().matches(payPassword, userWalletDTO.getPayPassword())) {
                return ResponseStatusVO.dataError("支付密码错误", null);
            }
        }
        int saveRows = userWithdrawService.saveWithdraw(jwtUser.getUserId(), withdrawType.byteValue(), clientApp.byteValue(),
                amount.setScale(2, BigDecimal.ROUND_HALF_UP), bankcardId == null ? 1 : bankcardId);
        if (saveRows == 1) {
            return ResponseStatusVO.ok("提现申请提交成功", null);
        } else {
            return ResponseStatusVO.dataError("提现金额必须小于等于可提现余额", null);
        }
    }

    /**
     * 获取可提现或转账的金额
     *
     * @return
     */
    @GetMapping("user/available")
    public ResponseStatusVO getAvailableWithdraw() {
        BigDecimal availableWithdraw = userWithdrawService.getAvailableWithdraw(SecurityUtils.getJwtUser().getUserId());
        return ResponseStatusVO.ok("获取可提现或可转账金额", availableWithdraw);
    }

    /**
     * 取消提现申请
     *
     * @param transactionNo
     * @return
     */
    @PostMapping("user/cancel")
    @SysLog(description = "用户取消提现申请")
    public ResponseStatusVO cancelWithdraw(String transactionNo) {
        UserWithdrawDO userWithdrawDO = userWithdrawService.getByTransactionNo(transactionNo);
        if (userWithdrawDO == null || userWithdrawDO.getWithdrawStatus().byteValue() != WithdrawStatusEnum.CHECKING.getValue()) {
            return ResponseStatusVO.dataError("交易编号不正确或提现申请不是审核中状态", null);
        }
        if (userWithdrawDO.getUserId() != SecurityUtils.getJwtUser().getUserId()) {
            return ResponseStatusVO.dataError("交易编号不属于此用户", null);
        }
        int updateRows = userWithdrawService.cancelWithdraw(transactionNo, userWithdrawDO.getVersion() + 1);
        if (updateRows == 1) {
            return ResponseStatusVO.ok("已取消提现", null);
        } else {
            return ResponseStatusVO.dataError("数据版本号有问题，在取消前提现记录已被更新", null);
        }
    }

    /**
     * 提现申请审核，注意权限配置，审核完成后，再由人工完成提现并确认或第三方系统完成提现自动确认
     *
     * @param transactionNo
     * @param withdrawStatus
     * @param description
     * @return
     */
    @PostMapping("admin/check")
    @SysLog(description = "后台提现申请审核")
    public ResponseStatusVO checkWithdraw(String transactionNo, Byte withdrawStatus, String description) {
        boolean isStatusError = withdrawStatus == null
                || (withdrawStatus != WithdrawStatusEnum.CHECKED.getValue().byteValue() && withdrawStatus != WithdrawStatusEnum.UNCHECKED.getValue().byteValue());
        if (isStatusError) {
            return ResponseStatusVO.dataError("审核状态错误，1通过，2未通过", null);
        }
        if (StringUtils.isEmpty(transactionNo)) {
            return ResponseStatusVO.dataError("交易编号不能为空", null);
        }
        UserWithdrawDO userWithdrawDO = userWithdrawService.getByTransactionNo(transactionNo);
        if (userWithdrawDO == null || userWithdrawDO.getWithdrawStatus().byteValue() != WithdrawStatusEnum.CHECKING.getValue()) {
            return ResponseStatusVO.dataError("交易编号不正确或提现申请不是审核中状态", null);
        }
        int updateRows = userWithdrawService.checkWithdraw(userWithdrawDO.getUserId(), userWithdrawDO.getId(), transactionNo,
                withdrawStatus, description, SecurityUtils.getJwtUser().getUserId(), userWithdrawDO.getVersion() + 1);
        if (updateRows == 1) {
            if (userWithdrawDO.getWithdrawType() == WithdrawTypeEnum.BANKCARD.getValue().byteValue()) {
                return ResponseStatusVO.ok("审核成功", null);
            }
            // 如果使用第三方如银联、微信或支付宝完成提现，则可以在此处自动确认提现，但可能会出现提现失败的情况，只要提现失败，都只能由用户重新发起提现
            boolean doWithdraw = userWithdrawService.completeWithdraw(userWithdrawDO.getId(), transactionNo, WithdrawStatusEnum.SUCCESS.getValue().byteValue(), userWithdrawDO.getUserId(),
                    userWithdrawDO.getAmount(), 0L, userWithdrawDO.getVersion() + 2,
                    userWithdrawDO.getWithdrawType(), userWithdrawDO.getWithdrawClientApp());
            if (doWithdraw) {
                return ResponseStatusVO.ok("已自动完成提现操作，提现" + WithdrawStatusEnum.findByValue(withdrawStatus.intValue()).getDes(), null);
            }
            return ResponseStatusVO.dataError("未自动成功完成提现操作，提现编号：" + userWithdrawDO.getId() + "， 提现交易号: " + transactionNo, null);
        } else {
            return ResponseStatusVO.dataError("可用余额不足，请检查用户可用余额是否大于等于提现金额，或数据版本号有问题，在审核前提现记录已被更新", null);
        }
    }

    /**
     * 由系统人工确认完成提现，注意权限配置
     *
     * @param transactionNo
     * @param withdrawStatus
     * @return
     */
    @PostMapping("admin/confirm-human")
    @SysLog(description = "后台人工完成提现操作")
    public ResponseStatusVO confirmWithdrawHuman(String transactionNo, Byte withdrawStatus) {
        boolean isStatusError = withdrawStatus == null
                || (withdrawStatus != WithdrawStatusEnum.SUCCESS.getValue().byteValue() && withdrawStatus != WithdrawStatusEnum.FAILURE.getValue().byteValue());
        if (isStatusError) {
            return ResponseStatusVO.dataError("审核状态错误，4成功，5失败", null);
        }
        if (StringUtils.isEmpty(transactionNo)) {
            return ResponseStatusVO.dataError("交易编号不能为空", null);
        }
        UserWithdrawDO userWithdrawDO = userWithdrawService.getByTransactionNo(transactionNo);
        if (userWithdrawDO == null || userWithdrawDO.getWithdrawType() != WithdrawTypeEnum.BANKCARD.getValue().byteValue()) {
            return ResponseStatusVO.dataError("非提现到银行卡的交易", null);
        }
        if (userWithdrawDO.getWithdrawStatus().byteValue() != WithdrawStatusEnum.CHECKED.getValue()) {
            return ResponseStatusVO.dataError("交易编号不正确或提现申请不是已通过状态", null);
        }
        boolean doWithdraw = userWithdrawService.completeWithdraw(userWithdrawDO.getId(), transactionNo, withdrawStatus, userWithdrawDO.getUserId(),
                userWithdrawDO.getAmount(), SecurityUtils.getJwtUser().getUserId(), userWithdrawDO.getVersion() + 1,
                userWithdrawDO.getWithdrawType(), userWithdrawDO.getWithdrawClientApp());
        if (doWithdraw) {
            return ResponseStatusVO.ok("已人工完成提现到银行卡操作，提现" + WithdrawStatusEnum.findByValue(withdrawStatus.intValue()).getDes(), null);
        }
        return ResponseStatusVO.dataError("未成功完成提现到银行卡操作，提现编号：" + userWithdrawDO.getId() + "， 提现交易号: " + transactionNo, null);
    }

    /**
     * 第三方系统完成提现
     *
     * @return
     */
    public ResponseStatusVO doWithdrawThirdParty() {
        return null;
    }

    @Autowired
    public void setUserWithdrawService(UserWithdrawService userWithdrawService) {
        this.userWithdrawService = userWithdrawService;
    }

    @Autowired
    public void setUserWalletService(UserWalletService userWalletService) {
        this.userWalletService = userWalletService;
    }
}
